#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/utsname.h>

#include "od_engine.h"
#include "retrans_send.h"
#include "od_framework.h"
#include "param_json.h"
#include "ui_defines.h"
#include "console_param.h"
#include "sw_monitor.h"
#include "rpc_response.h"

static char default_board_name[] = "9550 V3";
static char default_hard_ver[] = "V3.0.1";
static char default_verion[] = "V1.0.0";
static char default_sn[] = "RD9550AV320180001";
static char default_mac0[] = "00:24:68:95:8A:FE";
static char default_mac1[] = "00:24:68:95:9A:FE";
static char default_runtime[] = "00 hours 00 mins 00 secs";

static char default_load_post_name[] = "tx1_mq_trans";
static char default_import_file[] = "import.json";
static char default_export_file[] = "/tmp/export.json";

char software_date[32] = "Build@"__DATE__" "__TIME__;
char software_version[32] = "V3.1.4";
char system_version[32] = "V3.1.4";

/*notice name shoudl not overflow*/
#define PARAM_FILE_IP_MODE       "./param_default_mode_ip"
#define PARAM_FILE_V35_MODE      "./param_default_mode_V35"
#define PARAM_FILE_USER_1           "./param_user_sav1"
#define PARAM_FILE_USER_2           "./param_user_sav2"
#define PARAM_FILE_USER_3           "./param_user_sav3"


static int32_t act_sw_monitor_params(void *var_hdl, int offset, void *mem, int id);
static int32_t act_alarm_info_params(void *var_hdl, int offset, void *mem, int id);
static int32_t act_import_export_params(void *var_hdl, int offset, void *mem, int id);
static int32_t act_switch_ctrl_params(void *var_hdl, int offset, void *mem, int id);
static int32_t act_load_and_sav_params(void *var_hdl, int offset, void *mem, int id);


#define USER_PARAM_END {PT_NULL_, 0, 0, 0, "", 0, 0, JSPARA_ARG_NULL, NULL}

struct pjdesc pd_import[] = {
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(import_params, src_id), "src_id", sizeof(int), 0, JSPARA_ARG_S32(1001, 0, 10000000), NULL},
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(import_params, dst_id), "dst_id", sizeof(int), 0, JSPARA_ARG_S32(1002, 0, 10000000), NULL},
    {PT_STRI_ | PT_FMT_NOSAVE, 0, 1, OFFSET(import_params, post_name), "post_name", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_load_post_name), NULL},
    {PT_STRI_ | PT_FMT_NOSAVE, 0, 1, OFFSET(import_params, file_name), "file_name", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_import_file), NULL},
    USER_PARAM_END
};

hash_desc_t param_import = 
{
    .pjdesc = pd_import,
    .hash_tab = NULL,
};

struct pjdesc pd_export[] = {
    {PT_STRI_ | PT_FMT_NOSAVE, 0, 1, OFFSET(export_params, file_name), "file_name", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_export_file), NULL},
    USER_PARAM_END
};

hash_desc_t param_export = 
{
    .pjdesc = pd_export,
    .hash_tab = NULL,
};

struct pjdesc pd_sw_monitor[] = {
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(sw_monitor_params, reboot), "reboot", sizeof(int), 0, JSPARA_ARG_S32(0, 0, 1), act_sw_monitor_params},
    USER_PARAM_END
};

hash_desc_t desc_sw_monitor = 
{
    .pjdesc = pd_sw_monitor,
    .hash_tab = NULL,
};

struct pjdesc pd_alarm_info[] = {
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(alarm_info_params, alarm_info_pro_ctrl), "alarm_info_pro_ctrl", sizeof(int), 0, JSPARA_ARG_S32(OD_OFF, OD_OFF, OD_ON), act_alarm_info_params},
    USER_PARAM_END
};

hash_desc_t desc_alarm_info = 
{
    .pjdesc = pd_alarm_info,
    .hash_tab = NULL,
};

struct pjdesc pd_sys_info[] = {
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, board_name), "board_name", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_board_name), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, hard_ver), "hard_ver", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_hard_ver), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, odin_ver), "odin_ver", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_verion), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, kernel_ver), "kernel_ver", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_verion), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, dtb_ver), "dtb_ver", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_verion), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, sn), "sn", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_sn), NULL},    
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, mac0), "mac0", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_mac0), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, mac1), "mac1", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_mac1), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(system_info_params, runtime), "runtime", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(default_runtime), NULL},
    USER_PARAM_END
};

hash_desc_t sys_info_query = 
{
    .pjdesc = pd_sys_info,
    .hash_tab = NULL,
};

struct pjdesc pd_switch_ctrl[] = {
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(switch_ctrl_params, ftp_ctrl), "ftp_ctrl", sizeof(int), 0, JSPARA_ARG_S32(0, 0, 1), act_switch_ctrl_params},
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(switch_ctrl_params, ssh_ctrl), "ssh_ctrl", sizeof(int), 0, JSPARA_ARG_S32(0, 0, 1), act_switch_ctrl_params},
    USER_PARAM_END
};

hash_desc_t param_switch_ctrl = 
{
    .pjdesc = pd_switch_ctrl,
    .hash_tab = NULL,
};

struct pjdesc pd_load_and_sav[] = {
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(param_load_and_sav_params, load), "load", sizeof(int), 0, JSPARA_ARG_S32(PARAM_LOAD_NONE, PARAM_LOAD_NONE, PARAM_LOAD_USER_3), act_load_and_sav_params},
    {PT_SINT_ | PT_FMT_NOSAVE, 0, 1, OFFSET(param_load_and_sav_params, sav), "sav", sizeof(int), 0, JSPARA_ARG_S32(PARAM_SAV_NONE, PARAM_SAV_NONE, PARAM_SAV_USER3), act_load_and_sav_params},
    USER_PARAM_END
};

hash_desc_t param_load_and_sav = 
{
    .pjdesc = pd_load_and_sav,
    .hash_tab = NULL,
};


struct pjdesc pd_console[] = {
    {PT_STRU | PT_FMT_NOSAVE, 0,  1, OFFSET(console_param, import), "import", sizeof(import_params), (size_t)&param_import, JSPARA_ARG_NULL, act_import_export_params},
    {PT_STRU | PT_FMT_NOSAVE, 0,  1, OFFSET(console_param, export), "export", sizeof(export_params), (size_t)&param_export, JSPARA_ARG_NULL, act_import_export_params},
    {PT_STRU | PT_FMT_NOSAVE, 0,  1, OFFSET(console_param, load_and_sav), "load_and_sav", sizeof(param_load_and_sav_params), (size_t)&param_load_and_sav, JSPARA_ARG_NULL, NULL},
    {PT_STRU | PT_FMT_NOSAVE, 0,  1, OFFSET(console_param, sw_monitor), "sw_monitor", sizeof(sw_monitor_params), (size_t)&desc_sw_monitor, JSPARA_ARG_NULL, NULL},
    {PT_STRU | PT_FMT_NOSAVE, 0,  1, OFFSET(console_param, alarm_info), "alarm_info", sizeof(alarm_info_params), (size_t)&desc_alarm_info, JSPARA_ARG_NULL, NULL},
    {PT_STRU, 0,  1, OFFSET(console_param, sys), "sys", sizeof(system_info_params), (size_t)&sys_info_query, JSPARA_ARG_NULL, NULL},
    {PT_STRU | PT_FMT_NOSAVE, 0,  1, OFFSET(console_param, switch_ctrl), "switch_ctrl", sizeof(switch_ctrl_params), (size_t)&param_switch_ctrl, JSPARA_ARG_NULL, NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(console_param, version), "version", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(software_version), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(console_param, date), "date", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(software_date), NULL},
    {PT_STRI_ | PT_FMT_RDONLY, 0, 1, OFFSET(console_param, system_version), "system_version", OD_MAX_OBJ_NAME, 0, JSPARA_ARG_STR(system_version), NULL},
    USER_PARAM_END
};

static int export_param_packet(char *name, char *id, char *export_file)
{
    int32_t ret = OD_OK;
    char *tmp_cmd = NULL;
    tmp_cmd = (char *)od_calloc(1, 2 * OD_MAX_PATH_LEN);
    if(NULL == tmp_cmd)
    {
        RPTERR("od_calloc error");
        return OD_ERROR;
    }
    
    snprintf(tmp_cmd, 2 * OD_MAX_PATH_LEN, 
        "echo '{\"jsonrpc\": \"2.0\", \"method\": \"%s.set\", \"params\": \\c \' >> %s; cat %s.json >> %s; echo ', \"id\": \"%s\"}\r' >> %s;",
        name, export_file, name, export_file, id, export_file);
    ret = system(tmp_cmd);
    
    if(tmp_cmd != NULL)
    {
        od_free(tmp_cmd);
    }

    RPTWRN("export ret= %d", ret);
    return ret;
}

int32_t act_import_export_params(void *var_hdl, int offset, void *mem, int id)
{
    char *cmd = NULL;
    int32_t ret = OD_OK;
    int cmd_ret = 0;
    
    od_framework_t * framework = var_hdl;
    json_param_console *json_param = framework->param_table;
    console_param * params = &(json_param->mem);
    import_params *import = &(params->import);
    export_params *export = &(params->export);

    cmd = (char *)od_calloc(1, 2 * OD_MAX_PATH_LEN);
    if(NULL == cmd)
    {
        RPTERR("od_calloc error");
        return OD_ERROR;
    }
    
    RPTDBG("in %d", offset);
    
    switch (offset)
    {
        case OFFSET(console_param, import):
            
            snprintf(cmd, 2 * OD_MAX_PATH_LEN, "./rpc_load.out  -s %d -d %d -f %s -p %s",
                import->src_id, import->dst_id, import->file_name, import->post_name);
        
            cmd_ret = system(cmd);

            RPTWRN("import cmd_ret= %d", cmd_ret);
            if (0 != cmd_ret)
            {
                add_msg_to_err_table("import param fail !");
                ret = OD_ERROR;
            }
            break;
            
        case OFFSET(console_param, export):
            
            snprintf(cmd, 2 * OD_MAX_PATH_LEN, "rm %s -f", export->file_name);
            system(cmd);
            
            cmd_ret |= export_param_packet("network", "network", export->file_name);
            cmd_ret |= export_param_packet("hardware", "hardware", export->file_name);
            cmd_ret |= export_param_packet("receive", "receive", export->file_name);
            cmd_ret |= export_param_packet("snmp", "snmp", export->file_name);
            cmd_ret |= export_param_packet("encoder", "encoder", export->file_name);
            cmd_ret |= export_param_packet("decoder", "decoder", export->file_name);
            
            if (0 != cmd_ret)
            {
                add_msg_to_err_table("export param fail !");
                ret = OD_ERROR;
            }
            break;
            
        default:
            break;
    }

    if(cmd != NULL)
    {
        od_free(cmd);
    }
    
    return ret;
}

static int32_t act_sw_monitor_params(void *var_hdl, int offset, void *mem, int id)
{
    od_framework_t *framework = var_hdl;
    od_task_handle sw_monitor = ghash_find(framework->task_table, "sw_monitor");
    int value = 0;
    int ret = OD_OK;

    if(NULL == sw_monitor)
    {
        RPTWRN("sw_monitor params not found in hash table");
        return OD_ERROR;
    }

    RPTDBG("in %d", offset);
    switch (offset)
    {
       case OFFSET(sw_monitor_params, reboot):
            value = *(int *)mem;
            
            if(1 == value)
            {
                system("./script/reboot.sh &");
                *(int *)mem = 0;
            }
            break;

        default:
            break;
    }

    return ret;
}

static int32_t act_alarm_info_params(void *var_hdl, int offset, void *mem, int id)
{
    int ret = OD_OK;
    od_framework_t *framework = var_hdl;
    od_task_handle alarm_info = ghash_find(framework->task_table, "alarm_info");

    if(NULL == alarm_info)
    {
        RPTWRN("alarm_info params not found in hash table");
        return OD_ERROR;
    }

    RPTDBG("in %d", offset);
    switch (offset)
    {
        case OFFSET(alarm_info_params, alarm_info_pro_ctrl):
            break;

        default:
            break;
    }

    return ret;
}

static int32_t act_switch_ctrl_params(void *var_hdl, int offset, void *mem, int id)
{
    char cmd[64];
    int32_t ret = OD_OK;
    int cmd_ret = 0;
    
    od_framework_t * framework = var_hdl;
    json_param_console *json_param = framework->param_table;
    console_param * params = &(json_param->mem);
    switch_ctrl_params *switch_ctrl = &(params->switch_ctrl);
    
    RPTDBG("in %d", offset);
    
    switch (offset)
    {
        case OFFSET(switch_ctrl_params, ftp_ctrl):

            if(switch_ctrl->ftp_ctrl == 1)
            {
                memset(cmd, 0, sizeof(cmd));
                sprintf(cmd, "service vsftpd start");
                cmd_ret = system(cmd);
            }
            else
            {
                memset(cmd, 0, sizeof(cmd));
                sprintf(cmd, "service vsftpd stop");
                cmd_ret = system(cmd);
            }

            RPTWRN("switch_ctrl ftp_ctrl cmd_ret= %d", cmd_ret);
            if (0 != cmd_ret)
            {
                add_msg_to_err_table("switch_ctrl param fail !");
                ret = OD_ERROR;
            }
            break;
        case OFFSET(switch_ctrl_params, ssh_ctrl):

            if(switch_ctrl->ssh_ctrl == 1)
            {
                memset(cmd, 0, sizeof(cmd));
                sprintf(cmd, "service sshd start");
                cmd_ret = system(cmd);
            }
            else
            {
                memset(cmd, 0, sizeof(cmd));
                sprintf(cmd, "service sshd stop");
                cmd_ret = system(cmd);
            }

            RPTWRN("switch_ctrl ssh_ctrl cmd_ret= %d", cmd_ret);
            if (0 != cmd_ret)
            {
                add_msg_to_err_table("switch_ctrl param fail !");
                ret = OD_ERROR;
            }
            break;
            
        default:
            break;
    }
    
    return ret;

}


static int32_t act_load_and_sav_params(void *var_hdl, int offset, void *mem, int id)
{
    char cmd[64];
    int32_t ret = OD_OK;
    int cmd_ret = 0;
    int value = 0;
    import_params import;
    export_params export;

    RPTWRN("in %d", offset);
    
    switch (offset)
    {
        case OFFSET(param_load_and_sav_params, load):

            value = *(int *)mem;
            import.src_id = 200;
            import.dst_id = 500;//id of methodtrans
            strncpy( import.post_name, "tx1_mq_trans", OD_MAX_OBJ_NAME - 1);

            switch (value)
            {
                case PARAM_LOAD_NONE:
                    break;

                case PARAM_LOAD_IP_DEFAULT:
                    strncpy( import.file_name, PARAM_FILE_IP_MODE, OD_MAX_OBJ_NAME - 1);
                    break;

                case PARAM_LOAD_V35_DEFAULT:
                    strncpy( import.file_name, PARAM_FILE_V35_MODE, OD_MAX_OBJ_NAME - 1);
                    break;

                case PARAM_LOAD_USER_1:
                    strncpy( import.file_name, PARAM_FILE_USER_1, OD_MAX_OBJ_NAME - 1);
                    break;

                case PARAM_LOAD_USER_2:
                    strncpy( import.file_name, PARAM_FILE_USER_2, OD_MAX_OBJ_NAME - 1);
                    break;

                case PARAM_LOAD_USER_3:
                    strncpy( import.file_name, PARAM_FILE_USER_3, OD_MAX_OBJ_NAME - 1);
                    break;

                default:
                    break;
            }

            if(value==PARAM_LOAD_NONE)
            {
                /*init is PARAM_LOAD_NONE and do nothing*/
                break;
            }
            snprintf(cmd, 2 * OD_MAX_PATH_LEN, "./rpc_load.out  -s %d -d %d -f %s -p %s",
                import.src_id, import.dst_id, import.file_name, import.post_name);
            RPTWRN("import cmd_ %s", cmd);
            cmd_ret = system(cmd);
            
            RPTWRN("import cmd_ret= %d", cmd_ret);
            if (0 != cmd_ret)
            {
                add_msg_to_err_table("import param fail !");
                ret = OD_ERROR;
            }
            break;

        case OFFSET(param_load_and_sav_params, sav):

            value = *(int *)mem;
            RPTWRN("value %d", value);
            switch (value)
            {
                case PARAM_SAV_NONE:
                    break;
                case PARAM_SAV_USER1:
                    strncpy( export.file_name, PARAM_FILE_USER_1, OD_MAX_OBJ_NAME - 1);
                    break;

                case PARAM_SAV_USER2:
                    strncpy( export.file_name, PARAM_FILE_USER_2, OD_MAX_OBJ_NAME - 1);
                    break;

                case PARAM_SAV_USER3:
                    strncpy( export.file_name, PARAM_FILE_USER_3, OD_MAX_OBJ_NAME - 1);
                    break;

                default:
                    break;
            }

            if(value==PARAM_SAV_NONE)
            {
                /*init is PARAM_SAV_NONE and do nothing*/
                break;
            }

            snprintf(cmd, 2 * OD_MAX_PATH_LEN, "rm %s -f", export.file_name);
            system(cmd);
            
            cmd_ret |= export_param_packet("network", "network", export.file_name);
            cmd_ret |= export_param_packet("hardware", "hardware", export.file_name);
            cmd_ret |= export_param_packet("receive", "receive", export.file_name);
            cmd_ret |= export_param_packet("snmp", "snmp", export.file_name);
            cmd_ret |= export_param_packet("encoder", "encoder", export.file_name);
            cmd_ret |= export_param_packet("decoder", "decoder", export.file_name);
            
            if (0 != cmd_ret)
            {
                add_msg_to_err_table("export param fail !");
                ret = OD_ERROR;
            }

            break;
            
        default:
            break;
    }
    
    return ret;

}


int kernel_ver_get(char * buf)
{
    struct utsname kernel_info;

    if(uname(&kernel_info) == 0)
    {
        strncpy(buf, kernel_info.version + 16, strlen(kernel_info.version) - 16 - 18);
        return OD_OK;
    }
    else
    {
        RPTERR("can not get kernel version!");
        return OD_ERROR;
    }
}

int dtb_ver_get(char * buf)
{
    FILE *fp;
    if((fp=fopen("/proc/device-tree/version","r")))
    {
        fseek(fp, 11L, 0);
        fread(buf, OD_MAX_OBJ_NAME, 1, fp);
        fclose(fp);
        return OD_OK;
    }
    else
    {
        RPTERR("can not get dtb version!");
        return OD_ERROR;
    }
}

/*初始化默认参数*/
static void console_params_init(console_param *param)
{
    char buf[OD_MAX_OBJ_NAME];
    /*total*/
    memset(param, 0, sizeof(console_param));
    
    strncpy(param->export.file_name, default_export_file, OD_MAX_OBJ_NAME - 1);

    param->sw_monitor.reboot = 0;

    strncpy(param->sys.board_name, default_board_name, OD_MAX_OBJ_NAME - 1);
    strncpy(param->sys.hard_ver, default_hard_ver, OD_MAX_OBJ_NAME - 1);
    strncpy(param->sys.odin_ver, default_verion, OD_MAX_OBJ_NAME - 1);
    strncpy(param->sys.sn, default_sn, OD_MAX_OBJ_NAME - 1);
    strncpy(param->sys.mac0, default_mac0, OD_MAX_OBJ_NAME - 1);
    strncpy(param->sys.mac1, default_mac1, OD_MAX_OBJ_NAME - 1);


    param->switch_ctrl.ftp_ctrl = 0;
    param->switch_ctrl.ssh_ctrl = 0;

    memset(buf, '\0', sizeof(buf));
    if(kernel_ver_get(buf) == 0)
    {
        strncpy(param->sys.kernel_ver, buf, OD_MAX_OBJ_NAME - 1);
    }

    memset(buf, '\0', sizeof(buf));
    if(dtb_ver_get(buf) == 0)
    {
        strncpy(param->sys.dtb_ver, buf, OD_MAX_OBJ_NAME - 1);
    }

    strncpy(param->version, software_version, OD_MAX_OBJ_NAME - 1); /*进程版本号*/
    strncpy(param->date, software_date, OD_MAX_OBJ_NAME - 1);  /*编译日期*/
    strncpy(param->system_version, system_version, OD_MAX_OBJ_NAME - 1);
}

/*成功则返回0，失败返回小于0的数*/
int console_json_param_init(od_framework_t *frameworks, char *filename)
{
    json_param_console * params_obj = (json_param_console *)(frameworks->param_table);
    jsparam_args_t args;

    console_params_init(&(params_obj->mem));

    /****************json handle init, include  system json and  json table**********/
    args.mempt = &(params_obj->mem);
    args.pjdesc = pd_console;
    args.prj_hdl = frameworks;
    params_obj->json_hdl = jsparam_create(&args);

    if(NULL == params_obj->json_hdl)
    {
        return OD_ERROR;
    }

    RPTDBG("after jsparam_create");
    memset(params_obj->console_json_filename, 0, OD_MAX_PATH_LEN);    
    strncpy(params_obj->console_json_filename, filename, OD_MAX_PATH_LEN - 1);

    jsparam_load(params_obj->json_hdl, params_obj->console_json_filename);
    jsparam_sav(params_obj->json_hdl, params_obj->console_json_filename);

    return OD_OK;
}

void console_json_param_destroy(od_framework_t *frameworks)
{
    json_param_console * params_obj = (json_param_console *)(frameworks->param_table);

    jsparam_delete(params_obj);
}

